package com.dabai.iot.core.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dabai.common.core.utils.DateUtils;
import com.dabai.common.core.utils.Func;
import com.dabai.common.satoken.utils.LoginHelper;
import com.dabai.common.tdengine.core.TDEngineTemplate;
import com.dabai.common.tdengine.model.DataRecord;
import com.dabai.common.tdengine.model.TDField;
import com.dabai.iot.common.constant.IotKeyConstant;
import com.dabai.iot.common.enums.BizLogCode;
import com.dabai.iot.common.enums.BizLogType;
import com.dabai.iot.common.model.DeviceInfo;
import com.dabai.iot.common.model.IotMqttMessage;
import com.dabai.iot.common.model.IotMqttStatus;
import com.dabai.iot.core.dto.DeviceLogQuery;
import com.dabai.iot.core.service.IDeviceLogService;
import com.dabai.iot.core.task.BatchLogProcessor;
import com.dabai.iot.core.utils.IotTDSql;
import com.dream.flex.def.FunctionDef;
import com.dream.tdengine.mapper.FlexTdMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;

import static com.dream.flex.def.FunctionDef.col;
import static com.dream.flex.def.FunctionDef.table;

/**
 * 设备日志 Service 实现类
 *
 * @author kev1n
 */
@Service
@RequiredArgsConstructor
public class DeviceLogServiceImpl implements IDeviceLogService {

    private final TDEngineTemplate tdEngineTemplate;
    private final FlexTdMapper flexTdMapper;
    private final BatchLogProcessor batchLogProcessor;

    @Override
    public void createDeviceLogStb(String tenantId, String productKey) {
        String sTableName = IotTDSql.getDeviceLogStbName(tenantId, productKey);

        List<TDField> columnList = Arrays.asList(
            new TDField("ts", "timestamp", -1),
            new TDField("trace_id", "NCHAR", 64),
            new TDField("topic", "NCHAR", 128),
            new TDField("message", "NCHAR", 1024 * 8),
            new TDField("biz_type", "INT"),
            new TDField("operation", "NCHAR", 64),
            new TDField("code", "INT")
        );

        List<TDField> tagList = Collections.singletonList(
            new TDField("device_sn", "NCHAR", 64)
        );

        // 创建超级表
        tdEngineTemplate.createSTable(sTableName, columnList, tagList);
    }

    @Override
    public IPage<Map<String, Object>> getDeviceLogPageFromTD(IPage<Map<String, Object>> page, DeviceLogQuery deviceLogQuery) {
        String tableName = "";
        if (Func.isBlank(deviceLogQuery.getDeviceSn())) {
            tableName = IotTDSql.getDeviceLogStbName(LoginHelper.getTenantId(), deviceLogQuery.getProductKey());
        } else {
            tableName = IotTDSql.getDeviceLogTableName(deviceLogQuery.getProductKey(), deviceLogQuery.getDeviceSn());
        }

        // sql 拼接
        String sql = "SELECT * FROM `${tableName}` WHERE 1 = 1 ";
        // sql 参数
        Map<String, Object> params = new HashMap<>(8);
        params.put("tableName", tableName);
        // 跟踪ID判断
        String traceId = deviceLogQuery.getTraceId();
        if (Func.isNotBlank(traceId)) {
            sql += " and trace_id = '${traceId}'";
            params.put("traceId", traceId);
        }
        // 业务类型判断
        Integer bizType = deviceLogQuery.getBizType();
        if (Func.isNotEmpty(bizType)) {
            sql += " and `biz_type` = '${bizType}'";
            params.put("bizType", bizType);
        }
        // 时间筛选
        if (deviceLogQuery.getQueryStartTime() != null) {
            sql += " and ts >= '${time1}'";
            params.put("time1", DateUtils.formatDateTime(deviceLogQuery.getQueryStartTime()));
        }
        if (deviceLogQuery.getQueryEndTime() != null) {
            sql += " and ts <= '${time2}'";
            params.put("time2", DateUtils.formatDateTime(deviceLogQuery.getQueryEndTime()));
        }

        // 排序
        sql += " order by ts desc";
        return tdEngineTemplate.getPageBySql(page, sql, params);
    }

    @Override
    public void saveDeviceStatusLogToTD(DeviceInfo deviceInfo, IotMqttStatus mqttStatus) {
        String sTableName = IotTDSql.getDeviceLogStbName(deviceInfo.tenantId(), deviceInfo.productKey());
        String tableName = IotTDSql.getDeviceLogTableName(deviceInfo.productKey(), deviceInfo.deviceSn());

        Map<String, Object> params = new HashMap<>();
        params.put("ts", mqttStatus.reportTime().getTime());
        params.put("trace_id", mqttStatus.traceId());
        params.put("topic", null);
        params.put("message", null);
        params.put("biz_type", BizLogType.status.getValue());
        params.put("operation", mqttStatus.status().name());
        params.put("code", mqttStatus.logCode().getValue());

        String[] tags = new String[]{deviceInfo.deviceSn()};

        DataRecord dataRecord = new DataRecord();
        dataRecord.setSTableName(sTableName);
        dataRecord.setTableName(tableName);
        dataRecord.setParams(params);
        dataRecord.setTags(tags);

        batchLogProcessor.add(dataRecord);
    }

    @Override
    public void saveDeviceLogToTD(DeviceInfo deviceInfo, IotMqttMessage mqttMessage, BizLogType logBizType, BizLogCode logCode) {
        String sTableName = IotTDSql.getDeviceLogStbName(deviceInfo.tenantId(), deviceInfo.productKey());
        String tableName = IotTDSql.getDeviceLogTableName(deviceInfo.productKey(), deviceInfo.deviceSn());

        Map<String, Object> params = new HashMap<>();
        params.put("ts", mqttMessage.reportTime().getTime());
        params.put("trace_id", mqttMessage.traceId());
        params.put("topic", mqttMessage.topic());
        params.put("message", mqttMessage.payload());
        params.put("biz_type", logBizType.getValue());
        params.put("operation", mqttMessage.topic());
        params.put("code", logCode.getValue());

        String[] tags = new String[]{deviceInfo.deviceSn()};

        DataRecord dataRecord = new DataRecord();
        dataRecord.setSTableName(sTableName);
        dataRecord.setTableName(tableName);
        dataRecord.setParams(params);
        dataRecord.setTags(tags);

        batchLogProcessor.add(dataRecord);
    }

    @Override
    public void savePropertiesLogToTD(String productKey, String deviceSn, String jsonData) {
        JSONObject root = JSON.parseObject(jsonData);
        JSONArray blocks = root.getJSONArray(IotKeyConstant.BLOCKS);

        for (int i = 0; i < blocks.size(); i++) {
            JSONObject block = blocks.getJSONObject(i);
            String blockIdentifier = block.getString(IotKeyConstant.BLOCK_ID);
            JSONObject properties = block.getJSONObject(IotKeyConstant.PROPERTIES);
            long reportTime = block.getLongValue(IotKeyConstant.REPORT_TIME);

            // 1. 获取超级表名
            String sTableName = IotTDSql.getDevicePropertyStbName(productKey, blockIdentifier);

            // 2. 获取子表名
            String tableName = IotTDSql.getDevicePropertyTableName(productKey, blockIdentifier, deviceSn);

            // 2. 准备 TDengine 数据映射
            Map<String, Object> params = new HashMap<>();
            params.put("ts", reportTime);  // 必须字段

            // 3. 添加动态属性
            for (String key : properties.keySet()) {
                Object value = properties.get(key);
                // 实际场景可能需要类型转换（如字符串转数值）
                params.put(key, value);
            }

            String[] tags = new String[]{deviceSn};

            DataRecord dataRecord = new DataRecord();
            dataRecord.setSTableName(sTableName);
            dataRecord.setTableName(tableName);
            dataRecord.setParams(params);
            dataRecord.setTags(tags);
            batchLogProcessor.add(dataRecord);
        }
    }

    @Override
    public Long deviceMessageCount(String tenantId, String productKey, Date startTime, Date endTime) {
        String sTableName = IotTDSql.getDeviceLogStbName(tenantId, productKey).toLowerCase();

        return flexTdMapper.select(FunctionDef.count(col("*")))
            .from(table(sTableName))
            .where(col("ts").between(startTime, endTime))
            .one(Long.class);
    }

}
